/*
 * COPYRIGHT:	2010 Christopher Smith, licenced under the GNU GPL v2; see COPYING in the top level directory
 * PROJECT:		sdedit
 * FILE:		auto opts.h
 * PURPOSE:		SDE_OPTS * set copy with automatic memory management (C++ semantics)
 */

class auto_SDE_OPTS : public SDE_OPTS
{
private:
	void CopyFrom(SDE_OPTS src)
	{
		OptCount = src.OptCount;
		Opts = new SDE_OPT[src.OptCount];

		for(ULONG i = 0; i < src.OptCount; i++)
		{
			Opts[i].Name = src.Opts[i].Name;
			Opts[i].Type = src.Opts[i].Type;
			Opts[i].Flags = src.Opts[i].Flags;

			if(src.Opts[i].Flags & SDE_OPT_SET) //only copy if there is data to copy
				switch(src.Opts[i].Type)
				{
				case SptSubList: //always copy
					{
						Opts[i].SubList = new auto_SDE_OPTS(*src.Opts[i].SubList);
						Opts[i].Flags |= SDE_OPT_DATA_OWNERSHIP;
					}
					break;

				case SptString: //copy only if not owned elsewhere, but guarnteed to be available (probably owned by module)
					if(src.Opts[i].Flags & SDE_OPT_DATA_OWNERSHIP)
					{	
						auto_szpod<WCHAR> StringCopy = src.Opts[i].String;

						Opts[i].String = StringCopy.release_unsafe();
					}
					else
						Opts[i].String = src.Opts[i].String; //no need to make a copy of a string already guarnteed to be available
					break;

				case SptEnum:
				case SptMultiEnumOr: //always copy these
					Opts[i].Enum = new SDE_ENUM();
					*Opts[i].Enum = *src.Opts[i].Enum;
					Opts[i].Flags |= SDE_OPT_DATA_OWNERSHIP;
					break;

				case SptOther:
				case SptInt32:
				case SptInt32Hex:
				case SptBool:
				case SptPresent:
					Opts[i].Void = src.Opts[i].Enum;
					break;

				default:
					RaiseTextError(L"Invalid option type", L"Copying an option set");
					break;
				}
			else
				Opts[i].Void = NULL;
		}
	}

	static void DeleteArray(SDE_OPTS src)
	{
		for(ULONG i = 0; i < src.OptCount; i++)
		{
			switch(src.Opts[i].Type)
			{
			case SptSubList:
				if(src.Opts[i].Flags & SDE_OPT_DATA_OWNERSHIP)
				{
					DeleteArray(*src.Opts[i].SubList);
					delete src.Opts[i].SubList->Opts;
					delete src.Opts[i].SubList;
				}
				break;

			case SptString:
			case SptEnum:
			case SptMultiEnumOr: //always copy these
				if(src.Opts[i].Flags & SDE_OPT_DATA_OWNERSHIP)
					delete src.Opts[i].Void;
				break;

			case SptOther:
			case SptInt32:
			case SptInt32Hex:
			case SptBool:
			case SptPresent:
				break; //no indirect data-- no action

			default:
				RaiseTextError(L"Invalid option type", L"Copying an option set");
				break;
			}
		}
	}

	void DeleteThisArray()
	{
		DeleteArray(*this);
	}

public:
	auto_SDE_OPTS(auto_SDE_OPTS const &src)
	{
		CopyFrom(src);
	}

	auto_SDE_OPTS(SDE_OPTS const &src)
	{
		CopyFrom(src);
	}

	auto_SDE_OPTS(auto_take<SDE_OPTS> x)
	{
		OptCount = x.ptr->OptCount;
		Opts = x.ptr->Opts;
	}

	auto_SDE_OPTS()
	{
		OptCount = 0;
		Opts = NULL;
	}

	~auto_SDE_OPTS()
	{
		if(Opts)
		{
			DeleteThisArray();
			delete[] Opts;
		}
	}

	auto_SDE_OPTS &operator =(auto_SDE_OPTS const &x)
	{
		DeleteThisArray();
		CopyFrom(x);
		return *this;
	}

	auto_SDE_OPTS &operator =(SDE_OPTS const &x)
	{
		DeleteThisArray();
		CopyFrom(x);
		return *this;
	}

	auto_SDE_OPTS &operator =(auto_take<SDE_OPTS> x)
	{
		OptCount = x.ptr->OptCount;
		Opts = x.ptr->Opts;
	}
};